#include    "Matrix.h"


Matrix4::~Matrix4()
{
    delete array;
}

Matrix4::Matrix4()
{
    printf("Array \n");
    array = new float[16];
    Identity();
}

Matrix4::Matrix4(float * aArray)
{
    array= new float[16];

    for(int i=0;i<16;i++)
    {
        array[i]=aArray[i];
    }
}

Matrix4::Matrix4(const Matrix4 & mat)
{
    array = new float[16];

    for(int i=0;i<16;i++)
    {
            array[i]=mat.array[i];
    }
}

void Matrix4::operator=(const Matrix4 & mat)
{
    for(int i=0;i<16;i++)
    {
        array[i]=mat.array[i];
    }
}

Matrix4 Matrix4::operator*(Matrix4 mat2)
{
    float * aArray = new float[16];

    aArray[0]=(array[0]*mat2.array[0])+(array[1]*mat2.array[4])+(array[2]*mat2.array[8])+(array[3]*mat2.array[12]);
    aArray[1]=(array[0]*mat2.array[1])+(array[1]*mat2.array[5])+(array[2]*mat2.array[9])+(array[3]*mat2.array[13]);
    aArray[2]=(array[0]*mat2.array[2])+(array[1]*mat2.array[6])+(array[2]*mat2.array[10])+(array[3]*mat2.array[14]);
    aArray[3]=(array[0]*mat2.array[3])+(array[1]*mat2.array[7])+(array[2]*mat2.array[11])+(array[3]*mat2.array[15]);

    aArray[4]=(array[4]*mat2.array[0])+(array[5]*mat2.array[4])+(array[6]*mat2.array[8])+(array[7]*mat2.array[12]);
    aArray[5]=(array[4]*mat2.array[1])+(array[5]*mat2.array[5])+(array[6]*mat2.array[9])+(array[7]*mat2.array[13]);
    aArray[6]=(array[4]*mat2.array[2])+(array[5]*mat2.array[6])+(array[6]*mat2.array[10])+(array[7]*mat2.array[14]);
    aArray[7]=(array[4]*mat2.array[3])+(array[5]*mat2.array[7])+(array[6]*mat2.array[11])+(array[7]*mat2.array[15]);

    aArray[8]=(array[8]*mat2.array[0])+(array[9]*mat2.array[4])+(array[10]*mat2.array[8])+(array[11]*mat2.array[12]);
    aArray[9]=(array[8]*mat2.array[1])+(array[9]*mat2.array[5])+(array[10]*mat2.array[9])+(array[11]*mat2.array[13]);
    aArray[10]=(array[8]*mat2.array[2])+(array[9]*mat2.array[6])+(array[10]*mat2.array[10])+(array[11]*mat2.array[14]);
    aArray[11]=(array[8]*mat2.array[3])+(array[9]*mat2.array[7])+(array[10]*mat2.array[11])+(array[11]*mat2.array[15]);

    aArray[12]=(array[12]*mat2.array[0])+(array[13]*mat2.array[4])+(array[14]*mat2.array[8])+(array[15]*mat2.array[12]);
    aArray[13]=(array[12]*mat2.array[1])+(array[13]*mat2.array[5])+(array[14]*mat2.array[9])+(array[15]*mat2.array[13]);
    aArray[14]=(array[12]*mat2.array[2])+(array[13]*mat2.array[6])+(array[14]*mat2.array[10])+(array[15]*mat2.array[14]);
    aArray[15]=(array[12]*mat2.array[3])+(array[13]*mat2.array[7])+(array[14]*mat2.array[11])+(array[15]*mat2.array[15]);

    Matrix4 mat(aArray);

    return mat;
}

float * Matrix4::GetArray()
{
    printf("Return array \n");
    return array;
}

void Matrix4::Print()
{
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        {
            printf("%f, ", array[i*4+j]);
        }
        printf("\n");
    }
}

void Matrix4::Identity()
{
    array[0]=1; 	array[1]=0; 	array[2]=0; 	array[3]=0;
    array[4]=0; 	array[5]=1; 	array[6]=0; 	array[7]=0;
    array[8]=0; 	array[9]=0; 	array[10]=1; 	array[11]=0;
    array[12]=0;	array[13]=0; 	array[14]=0; 	array[15]=1;
}
void Matrix4::Translate(float x, float y, float z)
{
    Matrix4 mat;

    mat.array[3]=x;
    mat.array[7]=y;
    mat.array[11]=z;

    printf("Translate? \n");
    *this=(*this)*mat;
}

void Matrix4::Perspective(float angle, float ratio, float near, float far)
{
    float f= ((1.0) / (tan(angle / 2.0)));

    array[0]=f/ratio; 	array[1]=0; 	array[2]=0; 	array[3]=0;
    array[4]=0; 		array[5]=f; 	array[6]=0; 	array[7]=0;
    array[8]=0; 		array[9]=0; 	array[10]=((near+far)/(near-far)); 	array[11]=((2*near*far)/(near-far));
    array[12]=0;		array[13]=0; 	array[14]=-1; 	array[15]=1;
}

void Matrix4::Push()
{
    pile.push(*this);
}

void Matrix4::Pop()
{
    *this=pile.top();
    pile.pop();

}

void Matrix4::Rotatex(float angle)
{
    Matrix4 mat;
    mat.Identity();

    mat.array[0]=1; 	mat.array[1]=0; 			mat.array[2]=0; 			mat.array[3]=0;
    mat.array[4]=0; 	mat.array[5]=cos(angle); 	mat.array[6]=sin(angle); 	mat.array[7]=0;
    mat.array[8]=0; 	mat.array[9]=-sin(angle); 	mat.array[10]=cos(angle); 	mat.array[11]=0;
    mat.array[12]=0;	mat.array[13]=0; 			mat.array[14]=0; 			mat.array[15]=1;

    *this=*this * mat;

}

void Matrix4::Rotatey(float angle)
{
    Matrix4 mat;
    mat.Identity();

    mat.array[0]=cos(angle); 	mat.array[1]=0; 	mat.array[2]=sin(angle); 		mat.array[3]=0;
    mat.array[4]=0; 			mat.array[5]=1; 	mat.array[6]=0; 					mat.array[7]=0;
    mat.array[8]=-sin(angle); 	mat.array[9]=0; 	mat.array[10]=cos(angle); 		mat.array[11]=0;
    mat.array[12]=0;			mat.array[13]=0; 	mat.array[14]=0; 				mat.array[15]=1;

    *this=*this * mat;
}

void Matrix4::Rotatez(float angle)
{
	Matrix4 mat;
    mat.Identity();

    mat.array[0]=cos(angle); 	mat.array[1]=sin(angle); 	mat.array[2]=0; 			mat.array[3]=0;
    mat.array[4]=-sin(angle); 	mat.array[5]=cos(angle); 	mat.array[6]=0; 			mat.array[7]=0;
    mat.array[8]=0; 			mat.array[9]=0; 			mat.array[10]=1; 		mat.array[11]=0;
    mat.array[12]=0;			mat.array[13]=0; 			mat.array[14]=0; 		mat.array[15]=1;

    *this=*this * mat;;
}

Matrix4 Translation(float x, float y, float z)
{
    Matrix4 mat;
    mat.Translate(x,y,z);

    return mat;
}

Matrix4 Rotation(float x, float y, float z)
{
    Matrix4 matx, maty, matz;

    matx.Rotatex(x);
    maty.Rotatey(y);
    matz.Rotatez(z);

    return(matx*maty*matz);
}
